﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System;
using UnityEditor.Experimental.AssetImporters;
using System.IO;
using System.Text.RegularExpressions;

namespace Nirvana
{
	[Serializable]
	public enum TextureMaxSize
	{
		Size32 = 32,
		Size64 = 64,
		Size128 = 128,
		Size256 = 256,
		Size512 = 512,
		Size1024 = 1024,
		Size2048 = 2048,
		Size4096 = 4096,
	}

	/// <summary>
	/// Texture资源导入规则
	/// 注意：
	///     规则文件必须存放在资源的父目录或同一级目录下。便于不同资源模块的管理。
	/// </summary>
	[CreateAssetMenu(fileName = "@TextureImportRule", menuName = "Nirvana/Asset/TextureImportRule")]

	public sealed class TextureImportRule: ScriptableObject
	{
		/// <summary>
		/// 指定检测规则的资源
		/// </summary>
		[Tooltip("通过哪些资源.")]
		[SerializeField]
		private ListStringVariate includeRegexs;
		/// <summary>
		/// 忽略规则检测
		/// </summary>
		[Tooltip("排除哪些资源.")]
		[SerializeField]
		private ListStringVariate excludeRegexs;

	
		[SerializeField]
		private TextureImporterTypeVariate textureType;
		[Tooltip("2D/Cube")]
		[SerializeField]
		private TextureImporterShapeVariate textureShape;

		[SerializeField]
		private TextureWrapModeVariate wrapMode;
		[SerializeField]
		private FilterModeVariate filterMode;

		[Tooltip("各向异性过滤），提高数值改善极端视角下的贴图质量，比如地面，但耗性能")]
		[SerializeField]
		private IntVariate anisoLevel;



		[Tooltip("设置颜色空间：Gamma,Line")]
		[SerializeField]
		private BoolVariate sRGBTexture;
		[Tooltip("决定Alpha通道的值")]
		[SerializeField]
		private TextureImporterAlphaSourceVariate alphaSource;
		[SerializeField]
		[Tooltip("如果alpha通道是透明的，勾选这个选项，做颜色放大来修正边缘效果在固定半透明纹理上")]
		private BoolVariate alphaIsTransparency;

		[SerializeField]
		private TextureImporterNPOTScaleVariate nonPowerOf2;
		[SerializeField]
		private BoolVariate isReadable;
        [Tooltip("修补非4的倍数的图片")]
        [SerializeField]
        private BoolVariate isFix4Rate;

		/// <summary>
		/// 开启该功能的好处是可以节省关卡加载时间,通常，
		/// 这样的系统通过仅加载渲染场景中当前相机位置所需的mipmap来减少纹理所需的总内存量。
		/// 它可以节省少量CPU成本，从而节省大量GPU内存。
		/// </summary>
		[Tooltip("流式Mip,按需动态加载Mip数据到内存，而不是全部加载")]
		[SerializeField]
		private BoolVariate streamingMipmaps;
		[Tooltip("此属性用于设置 Mipmap 的优先级")]
		[SerializeField]
		private IntVariate StreamingMipMapPriority;


		[SerializeField]
		private BoolVariate mipmapEnabled;
		[Tooltip("启用此属性可避免颜色向外渗透到较低 MIP 级别的边缘。该功能用于光照剪影（见下文）。默认情况下会禁用此属性。")]
		[SerializeField]
		private BoolVariate borderMipmap;

		[Tooltip("有两种 Mipmap 过滤方法可用于优化图像质量。默认选项为 Box。")]
		[SerializeField]
		private TextureImporterMipFilterVariate mipmapFilter;
		/// <summary>
		/// 正偏差会使纹理看起来更加模糊，负偏差会锐化 纹理。
		/// 注意，使用较大的负偏差会降低性能，因此不建议使用 超过 -0.5 的负偏差
		/// </summary>
		[Tooltip("纹理的多级渐进纹理偏差。")]
		[SerializeField]
		private FloatVariate mipMapBias;

		/// <summary>
		/// 如果希望生成的 Mipmap 的 Alpha 通道在 Alpha Test期间保留覆盖率
		/// 改善Cutout材质（亦即alpha tested材质）
		/// </summary>
		[SerializeField]
		private BoolVariate mipMapsPreserveCoverage;
		/// <summary>
		/// 设置用于在 Alpha Test期间控制 MipMap 覆盖范围的参考值。
		/// </summary>
		[SerializeField]
		private FloatVariate alphaCoutoffValue;

		/// <summary>
		///  启用此属性可在 MIP 级别递进时使 Mipmap 淡化为灰色。此属性用于细节贴图。
		/// </summary>
		[SerializeField]
		private BoolVariate fadeout;
		/// <summary>
		/// 第一个开始淡出的 MIP 级别
		/// </summary>
		[SerializeField]
		private IntVariate mipmapFadeDistanceStart;
		/// <summary>
		/// 纹理完全变灰的 MIP 级别。
		/// </summary>
		[SerializeField]
		private IntVariate mipmapFadeDistanceEnd;

		/// <summary>
		/// 允许在相关平台上对此纹理进行 Alpha 通道分离。
		/// </summary>
		[SerializeField]
		private BoolVariate allowAlphaSplitting;


		//[SerializeField]
		//private TextureImporterCompressionVariate textureCompression;


		/// <summary>
		/// 转换高度图为法线图，用于指定一些高度图，自动转换NormalMap格式
		/// 比如：自动转化任何文件名中带有 "_bumpmap"的纹理文件为法线贴图
		/// </summary>
	
		[SerializeField]
		private BoolVariate convertToNormalmap;

		[SerializeField]
		private TextureImporterNormalFilterVariate normalmapFilter;

		[SerializeField]
		private FloatVariate heightmapScale;
	
		[SerializeField]
		private TextureImporterGenerateCubemapVariate generateCubemap;
	
		[SerializeField]
		private TextureImporterFormatVariate androidTextureFormatNoAlpha;
		[SerializeField]
		private TextureImporterFormatVariate androidTextureFormatAlpha;
		[SerializeField]
		private TextureImporterFormatVariate iosTextureFormatNoAlpha, iosTextureFormatAlpha;
        [SerializeField]
        private TextureImporterFormatVariate webGLTextureFormat;
        [SerializeField]
		private TextureMaxSizeVariate maxTextureSize;
		[Tooltip("品质0-100")]
		[SerializeField]
		private IntVariate compressionQuality;

		// 针对Android平台Unity还实现了一套Crunched（紧缩）压缩方式，比如RGBA Crunched ETC2，先ETC2先压缩，
		// 然后在Crunched压缩，运行时在额外解压缩，所以大小更下，加载更快。
		//[SerializeField]
		//private BoolVariate crunchedCompression;


		private bool isEnd = true;
		public void SetIsCanProcess(bool flag)
		{
			isEnd = flag;
		}

		/// <summary>
		/// 返回当前配置脚本的存放目录
		/// </summary>
		/// <returns></returns>
		public string GetDirectorName()
		{
			string assetpath = AssetDatabase.GetAssetPath(this);
			return Path.GetDirectoryName(assetpath);
		}
		public static TextureImportRule[] GetAllAssetImportRule()
		{
			string[] allRules = AssetDatabase.FindAssets("t:TextureImportRule");
			List<TextureImportRule> tmps = new List<TextureImportRule>(allRules.Length);
			foreach (var p in allRules)
			{
				string guid = AssetDatabase.GUIDToAssetPath(p);
				tmps.Add(AssetDatabase.LoadAssetAtPath<TextureImportRule>(guid));
			}
			return tmps.ToArray();
		}

		public bool IsMatchRegex(string assetPath)
		{
			if (!isEnd) return false;
			if (!includeRegexs.IsHasValue()) return false;

			string ruleDirname = GetDirectorName();
			ruleDirname = ruleDirname.Replace('/', '\\');
			if (ruleDirname[ruleDirname.Length - 1] != Path.DirectorySeparatorChar) ruleDirname += Path.DirectorySeparatorChar;

			string filename = assetPath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
			//同一父目录下才检测规则
			if (!filename.StartsWith(ruleDirname, System.StringComparison.OrdinalIgnoreCase)) return false;

			//指定包含的规则
			var temparray = this.includeRegexs.GetValue().ToArray();
			Regex[] regexs = null;
			if (temparray != null && temparray.Length > 0)
			{
				regexs = new Regex[temparray.Length];
				for (int i = 0; i < temparray.Length; i++) regexs[i] = new Regex(temparray[i]);
			}

			//需要忽略的规则
			temparray = this.excludeRegexs.GetValue().ToArray();
			Regex[] exRegexs = null;
			if (temparray != null && temparray.Length > 0)
			{
				exRegexs = new Regex[temparray.Length];
				for (int i = 0; i < temparray.Length; i++) exRegexs[i] = new Regex(temparray[i]);
			}

			string input = DirectoryUtil.RelativePath(GetDirectorName(), assetPath);
			if (regexs != null)
			{
				bool flag = false;
				foreach (Regex r in regexs)
				{
					if (r.IsMatch(input))
					{
						flag = true;
					}
				}
				if (!flag)
				{
					return false;
				}
			}
			if (exRegexs != null)
			{
				bool flag2 = false;
				foreach (Regex r in exRegexs)
				{
					if (r.IsMatch(input))
					{
						flag2 = true;
						break;
					}
				}
				if (flag2)
				{
					return false;
				}
			}
			return true;
		}


        /// <summary>
        /// 修补非4的倍数吃饭图片
        /// </summary>
        /// <param name="path"></param>
        public void FixImageNot4Rate(TextureImporter importer, Texture2D texture2D)
        {
            if (this.isFix4Rate.IsHasValue() && this.isFix4Rate.GetValue())
            {
                if (texture2D == null)
                {
                    return;
                }

                if (!isNeedFixSize(texture2D))
                {
                    return;
                }
                bool isReadable = importer.isReadable;
                if (isReadable == false)
                {
                    importer.isReadable = true;
                    importer.SaveAndReimport();
                }

                // 采样创建新贴图
                Texture2D tempTexture = Build4RateTexture2d(texture2D);
                Output4RateTexture(tempTexture, importer.assetPath);
                // 还原是否可写
                if (!isReadable)
                {
                    importer.isReadable = false;
                    importer.SaveAndReimport();
                }
                //Debug.Log("Fix 4x Texture: " + importer.assetPath);
                AssetDatabase.Refresh();
            } 
        }

        /// <summary>
        /// 是否需要修复尺寸
        /// </summary>
        private bool isNeedFixSize(Texture2D texture2D)
        {
            bool widthIs4Rate = Is4Rate(texture2D.width);
            bool heightIs4Rate = Is4Rate(texture2D.height);
            if (widthIs4Rate && heightIs4Rate)
            {
                return false;
            }
            return true;
        }

        /// <summary>
        /// 输出新的特图信息
        /// </summary>
        private void Output4RateTexture(Texture2D tempTexture, string path)
        {
            // 保存新的贴图
            byte[] dataBytes = null;
            // 数据根据原文件类型转换
            string Ext = Path.GetExtension(path);
            if (Ext.ToLower() == ".png")
            {
                dataBytes = tempTexture.EncodeToPNG();
            }
            else if (Ext.ToLower() == ".jpg")
            {
                dataBytes = tempTexture.EncodeToJPG();
            }
            else if (Ext.ToLower() == ".tga")
            {
                dataBytes = tempTexture.EncodeToTGA();
            }
            if (dataBytes != null)
            {
                File.WriteAllBytes(path, dataBytes);
            }
        }

        /// <summary>
        /// 重新创建贴图进行采样
        /// </summary>
        private Texture2D Build4RateTexture2d(Texture2D texture2D)
        {
            // 生成新的材质
            int fixWidth = texture2D.width % 4 == 0 ? 0 : 4 - texture2D.width % 4;
            int fixHeight = texture2D.height % 4 == 0 ? 0 : 4 - texture2D.height % 4;
            // 像素偏移
            int offsetWidth = fixWidth == 0 ? 0 : 1;
            int offsetHeight = fixHeight == 0 ? 0 : 1;
            Texture2D tempTexture = new Texture2D(texture2D.width + fixWidth, texture2D.height + fixHeight);
            for (int i = 0; i < tempTexture.width; i++)
            {
                for (int j = 0; j < tempTexture.height; j++)
                {
                    tempTexture.SetPixel(i, j, Color.clear);
                }
            }
            Color[] tempColor = texture2D.GetPixels();
            tempTexture.SetPixels(offsetWidth, offsetHeight, texture2D.width, texture2D.height, tempColor);
            return tempTexture;
        }

        /// <summary>
        /// 是否是4的倍数
        /// </summary>
        /// <param name="num"></param>
        /// <returns></returns>
        private bool Is4Rate(int num)
        {
            int result = num % 4;
            if (result == 0)
            {
                return true;
            }
            return false;
        }



		public void MatchRule(TextureImporter import)
		{
			bool isChange = false;
			if (this.textureType.IsHasValue())
			{
				import.textureType = this.textureType.GetValue();
				isChange = true;
			}

			if (this.textureShape.IsHasValue())
			{
				import.textureShape = this.textureShape.GetValue();
				isChange = true;
			}

			if (this.sRGBTexture.IsHasValue())
			{
				import.sRGBTexture = this.sRGBTexture.GetValue();
				isChange = true;
			}
			if (this.mipmapFilter.IsHasValue())
			{
				import.mipmapFilter = this.mipmapFilter.GetValue();
				isChange = true;
			}
			if (this.fadeout.IsHasValue())
			{
				import.fadeout = this.fadeout.GetValue();
				isChange = true;
			}
			if (this.mipmapFadeDistanceStart.IsHasValue())
			{
				import.mipmapFadeDistanceStart = this.mipmapFadeDistanceStart.GetValue();
				isChange = true;
			}
			if (this.mipmapFadeDistanceEnd.IsHasValue())
			{
				import.mipmapFadeDistanceEnd = this.mipmapFadeDistanceEnd.GetValue();
				isChange = true;
			}
			if (this.convertToNormalmap.IsHasValue())
			{
				import.convertToNormalmap = this.convertToNormalmap.GetValue();
				isChange = true;
			}
			if (this.normalmapFilter.IsHasValue())
			{
				import.normalmapFilter = this.normalmapFilter.GetValue();
				isChange = true;
			}
			if (this.borderMipmap.IsHasValue())
			{
				import.borderMipmap = this.borderMipmap.GetValue();
				isChange = true;
			}
			if (this.heightmapScale.IsHasValue())
			{
				import.heightmapScale = this.heightmapScale.GetValue();
				isChange = true;
			}
			if (this.filterMode.IsHasValue())
			{
				import.filterMode = this.filterMode.GetValue();
				isChange = true;
			}
			if (this.wrapMode.IsHasValue())
			{
				import.wrapMode = this.wrapMode.GetValue();
				isChange = true;
			}
			if (this.mipMapBias.IsHasValue())
			{
				import.mipMapBias = this.mipMapBias.GetValue();
				isChange = true;
			}
            if (this.mipMapsPreserveCoverage.IsHasValue())
            {
				import.mipMapsPreserveCoverage = this.mipMapsPreserveCoverage.GetValue();
				if (this.alphaCoutoffValue.IsHasValue()) import.alphaTestReferenceValue = this.alphaCoutoffValue.GetValue();
				isChange = true;
			}
			if (this.alphaIsTransparency.IsHasValue())
			{
				import.alphaIsTransparency = this.alphaIsTransparency.GetValue();
				isChange = true;
			}
			
			if (this.anisoLevel.IsHasValue())
			{
				import.anisoLevel = this.anisoLevel.GetValue();
				isChange = true;
			}
			if (this.streamingMipmaps.IsHasValue())
			{
				import.streamingMipmaps = this.streamingMipmaps.GetValue();
				if (this.StreamingMipMapPriority.IsHasValue())
				{
					import.streamingMipmapsPriority = this.StreamingMipMapPriority.GetValue();
				}
				isChange = true;
			}

			if (this.mipmapEnabled.IsHasValue())
			{
				import.mipmapEnabled = this.mipmapEnabled.GetValue();
				isChange = true;

			}
			
			if (this.isReadable.IsHasValue())
			{
				import.isReadable = this.isReadable.GetValue();
				isChange = true;
			}
			if (this.nonPowerOf2.IsHasValue())
			{
				import.npotScale = this.nonPowerOf2.GetValue();
				isChange = true;
			}

			//if (this.textureCompression.IsHasValue())
			//{
			//	import.textureCompression = this.textureCompression.GetValue();
			//  isChange = true;
			//}
			if (this.alphaSource.IsHasValue())
			{
				import.alphaSource = this.alphaSource.GetValue();
				isChange = true;
			}
			if (this.allowAlphaSplitting.IsHasValue())
			{
				import.allowAlphaSplitting = this.allowAlphaSplitting.GetValue();
				isChange = true;
			}
			if (this.generateCubemap.IsHasValue())
			{
				import.generateCubemap = this.generateCubemap.GetValue();
				isChange = true;
			}
			
			//TextureFormat
			var settings = import.GetPlatformTextureSettings("Android");
			if (this.androidTextureFormatNoAlpha.IsHasValue() && this.androidTextureFormatAlpha.IsHasValue())
			{
                //var settings = import.GetPlatformTextureSettings("Android");
                settings.overridden = true;
                if (import.DoesSourceTextureHaveAlpha()) //透明格式
                {
                    settings.format = androidTextureFormatAlpha.GetValue();
                }
                else
                {
                    settings.format = androidTextureFormatNoAlpha.GetValue();
                }



                import.SetPlatformTextureSettings(settings);
                isChange = true;
            }

			if (this.iosTextureFormatNoAlpha.IsHasValue() && this.iosTextureFormatAlpha.IsHasValue())
			{
                //iPhone平台图片格式设置
                settings = import.GetPlatformTextureSettings("iPhone");
                settings.overridden = true;
                if (import.DoesSourceTextureHaveAlpha())
                {
                    settings.format = iosTextureFormatAlpha.GetValue();
                }
                else
                {
                    settings.format = iosTextureFormatNoAlpha.GetValue();
                }



                import.SetPlatformTextureSettings(settings);
                isChange = true;
            }
            if (this.webGLTextureFormat.IsHasValue())
            {
                //webgl平台图片格式设置
                settings = import.GetPlatformTextureSettings("WebGL");
                settings.overridden = true;
                settings.format = webGLTextureFormat.GetValue();



                import.SetPlatformTextureSettings(settings);
                isChange = true;
            }

            if (this.maxTextureSize.IsHasValue())
			{
				import.maxTextureSize = (int)this.maxTextureSize.GetValue();

				settings.maxTextureSize = (int)this.maxTextureSize.GetValue();
				import.SetPlatformTextureSettings(settings);
				isChange = true;
			}
			if (this.compressionQuality.IsHasValue())
			{
				import.compressionQuality = this.compressionQuality.GetValue();
				settings.compressionQuality = this.compressionQuality.GetValue();
				import.SetPlatformTextureSettings(settings);
				isChange = true;
			}

            //if (this.crunchedCompression.IsHasValue())
            //{
            //	import.crunchedCompression = this.crunchedCompression.GetValue();
            //}
#if UNITY_2019_1_OR_NEWER
			    if (isChange) import.SaveAndReimport(); //unity2019版本需要主动刷新
#endif


        }

        private int GetMaxSize(TextureImporter import)
        {
            int w = 2048, h = 2048;
            int maxW = 2048, maxH = 2048;
            int maxSize = 2048;
#if UNITY_2022
			import.GetSourceTextureWidthAndHeight(out w, out h);
#endif
            if (w <= 128)
            {
                maxW = 128;
            }
            else if (w <= 256)
            {
                maxW = 256;
            }
            else if (w <= 512)
            {
                maxW = 512;
            }
            else if (w <= 1024)
            {
                maxW = 1024;
            }
            else
            {
                maxW = 2048;
            }

            if (h <= 128)
            {
                maxH = 128;
            }
            else if (h <= 256)
            {
                maxH = 256;
            }
            else if (h <= 512)
            {
                maxH = 512;
            }
            else if (h <= 1024)
            {
                maxH = 1024;
            }
            else
            {
                maxH = 2048;
            }

            if (maxH == maxW)
            {
                maxSize = maxW;
            }
            else
            {
                maxSize = maxW > maxH ? maxW : maxH;
            }

            return maxSize;
        }

    }
}

